package org.bing.engine.common.multicast;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.util.ArrayList;
import java.util.List;

import org.bing.engine.utility.helper.ThreadHelper;

public class MulticastServer {
    public static final int MAX_DATAGRAMPACKET_LENGTH = 1 * 1024;

    protected String multicastIp;
    protected InetAddress multicastAddress;
    protected int multicastPort;

    protected MulticastSocket multicastSocket;
    private List<MulticastHandler> handlers = new ArrayList<MulticastHandler>();

    public MulticastServer() {

    }

    public MulticastServer(String multicastIp, int multicastPort) {
        this.multicastIp = multicastIp;
        this.multicastPort = multicastPort;
    }

    private void clean() {
        if (multicastSocket != null) {
            multicastSocket.disconnect();
            multicastSocket.close();
        }
    }

    private void build() {
        try {
            multicastAddress = InetAddress.getByName(multicastIp);
            multicastSocket = new MulticastSocket(multicastPort);
            multicastSocket.joinGroup(multicastAddress);
        } catch (IOException e) {
            throw new RuntimeException("Generate multicast client error!", e);
        }
    }

    public void addHandler(MulticastHandler handler) {
        this.handlers.add(handler);
    }

    public void setHandlers(List<MulticastHandler> handlers) {
        this.handlers = handlers;
    }

    public void start() {
        while (true) {
            byte[] arb = new byte[MAX_DATAGRAMPACKET_LENGTH];
            DatagramPacket datagramPacket = new DatagramPacket(arb, arb.length);
            try {
                if (multicastSocket == null) {
                    build();
                }
                multicastSocket.receive(datagramPacket);
                this.handle(datagramPacket);
            } catch (IOException e) {
                clean();
                ThreadHelper.sleep(5000);
                build();
            }
        }
    }

    // TODO with client, handle msg security
    private void handle(DatagramPacket packet) {
        InetAddress addr = packet.getAddress();
        int port = packet.getPort();
        int len = packet.getLength();
        String msg = new String(packet.getData(), 0, len);
        for (int i = 0; i < handlers.size(); i++) {
            MulticastHandler handle = (MulticastHandler) handlers.get(i);
            handle.handle(addr, port, msg);
        }
    }

    public void shutdown() {
        if (multicastSocket != null) {
            multicastSocket.close();
        }
    }

    public String getMulticastIp() {
        return multicastIp;
    }

    public void setMulticastIp(String multicastIp) {
        this.multicastIp = multicastIp;
    }

    public int getMulticastPort() {
        return multicastPort;
    }

    public void setMulticastPort(int multicastPort) {
        this.multicastPort = multicastPort;
    }

    public static void main(String[] arstring) {
        try {
            MulticastServer ms = new MulticastServer("239.0.0.1", 7892);
            ms.addHandler(new AbstractHandler() {
                @Override
                public void handle(InetAddress addr, String msg) {
                    System.out.println(addr + "> " + msg);
                }
            });
            ms.start();
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }

}